package util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.Normalizer;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import javax.persistence.EmbeddedId;
import javax.persistence.Id;

/**
 * Biblioteca de métodos úteis.
 *
 * @author Rodolpho
 */
public abstract class LibUtil {

    /**
     * Retira os caracteres especiais da String passada por parâmetro
     *
     * @param texto
     * @return String
     */
    public static String retirarCaracteresEspeciais(String texto) {
        texto = Normalizer.normalize(texto, Normalizer.Form.NFD);
        return texto.replaceAll("[^\\p{ASCII}]", "");
    }

    /**
     * Retorna a string contendo a quebra de linha.
     *
     * @return String
     */
    public static String pularLinha() {
        return System.getProperty("line.separator");
    }

    /**
     * Retorna a string contendo a tabulação.
     *
     * @return String
     */
    public static String tabLinha() {
        return "    ";
    }

    /**
     * Printa as informações da exceção passada por parâmetro.
     *
     * @param e
     */
    public static void printMsgExcecao(CustomException e) {
        System.err.println("*** Exceção gerada ***" + LibUtil.pularLinha());
        System.err.println("Código: " + e.getErroId());
        System.err.println("Descrição: " + e.getErroDescricao());
        System.err.println("Mensagem Original: " + e.getErroMsgOriginal() + LibUtil.pularLinha());
        System.err.println("**********************" + LibUtil.pularLinha());
    }

    /**
     * Retorna a string formatada com a quantidade de tabs informada por
     * parâmetro.
     *
     * @param campo
     * @param texto
     * @param tabs
     * @return String
     */
    public static String tabFormatar(String texto, int tabs) {
        int tam = tabs - texto.length();
        String espaco = "";

        for (int cont = 0; cont < tam; cont++) {
            espaco += " ";
        }

        return espaco;
    }

    /**
     * Retorna a string criptografada utilizando a técnica MD5.
     *
     * @param texto
     * @return String
     */
    public static String encryptMD5(String texto) throws CustomException {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            BigInteger hash = new BigInteger(1, md.digest(texto.getBytes()));
            String s = hash.toString(16);
            if (s.length() % 2 != 0) {
                s = "0" + s;
            }
            return s;
        } catch (Exception e) {
            throw new CustomException("Falha ao criptografar utilizando MD5.", e);
        }
    }

    /**
     * Retorna o nome do atributo que possui a anotação Id ou a anotação
     * EmbeddedId (JPA).
     *
     * @param clazz
     * @param obj
     * @return String
     */
    public static Field getId(Class<?> clazz) throws CustomException {
        try {
            for (Method method : clazz.getDeclaredMethods()) {
                if ((method.getAnnotation(Id.class) != null) || (method.getAnnotation(EmbeddedId.class) != null)) {
                    String att = method.getName();
                    if (method.getName().substring(0, 3).contains("get")) {
                        att = method.getName().substring(3);
                    } else if (method.getName().substring(0, 2).contains("is")) {
                        att = method.getName().substring(2);
                    }
                    String prefix = att.substring(0, 1).toLowerCase();
                    String sufix = att.substring(1);
                    String finalString = prefix + sufix;
                    Field privateField = clazz.getDeclaredField(finalString);
                    privateField.setAccessible(true);
                    return privateField;
                }
            }
        } catch (Exception e) {
            throw new CustomException("Falha ao obter atributo Id da classe " + clazz.getName() + ".", e);
        }

        return null;
    }

    /**
     * Converte uma String para um objeto Byte. Caso a String seja vazia ou
     * nula, retorna null - para facilitar em casos onde formulários podem ter
     * campos numéricos vazios.
     *
     * @param value String numérica
     * @return Byte Objeto Byte ou null caso receba uma String vazia ou nula
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static Byte stringToByte(String value) throws CustomException {
        if (value == null || value.equals("")) {
            return null;
        }

        Byte byteValue = null;
        try {
            byteValue = java.lang.Byte.parseByte(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para Byte.", e);
        }
        return byteValue;
    }

    /**
     * Converte uma String para um tipo primitivo byte.
     *
     * @param value String numérica
     * @return byte primitivo
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static byte stringToBytePrimitive(String value) throws CustomException {
        try {
            return java.lang.Byte.parseByte(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para byte.", e);
        }
    }

    /**
     * Converte uma String para um objeto Short. Caso a String seja vazia ou
     * nula, retorna null - para facilitar em casos onde formulários podem ter
     * campos numéricos vazios.
     *
     * @param value String numérica
     * @return Short Objeto Short ou null caso receba uma String vazia ou nula
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static Short stringToShort(String value) throws CustomException {
        if (value == null || value.equals("")) {
            return null;
        }

        Short shortValue = null;
        try {
            shortValue = java.lang.Short.parseShort(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para Short.", e);
        }
        return shortValue;
    }

    /**
     * Converte uma String para um tipo primitivo short.
     *
     * @param value String numérica
     * @return short primitivo
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static short stringToShortPrimitive(String value) throws CustomException {
        try {
            return java.lang.Short.parseShort(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para short.", e);
        }
    }

    /**
     * Converte uma String para um objeto Integer. Caso a String seja vazia ou
     * nula, retorna null - para facilitar em casos onde formulários podem ter
     * campos numéricos vazios.
     *
     * @param value String numérica
     * @return Integer Objeto Integer ou null caso receba uma String vazia ou
     * nula
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static Integer stringToInteger(String value) throws CustomException {
        if (value == null || value.equals("")) {
            return null;
        }

        Integer integerValue = null;
        try {
            integerValue = java.lang.Integer.parseInt(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para Integer.", e);
        }
        return integerValue;
    }

    /**
     * Converte uma String para um tipo primitivo int.
     *
     * @param value String numérica
     * @return int primitivo
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static int stringToIntegerPrimitive(String value) throws CustomException {
        try {
            return java.lang.Integer.parseInt(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para integer.", e);
        }
    }

    /**
     * Converte uma String para um objeto Long. Caso a String seja vazia ou
     * nula, retorna null - para facilitar em casos onde formulários podem ter
     * campos numéricos vazios.
     *
     * @param value String numérica
     * @return Long Objeto Long ou null caso receba uma String vazia ou nula
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static Long stringToLong(String value) throws CustomException {
        if (value == null || value.equals("")) {
            return null;
        }

        Long longValue = null;
        try {
            longValue = java.lang.Long.parseLong(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para Long.", e);
        }
        return longValue;
    }

    /**
     * Converte uma String para um tipo primitivo long.
     *
     * @param value String numérica
     * @return long primitivo
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static long stringToLongPrimitive(String value) throws CustomException {
        try {
            return java.lang.Long.parseLong(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para long.", e);
        }
    }

    /**
     * Converte uma String para um objeto Float. Caso a String seja vazia ou
     * nula, retorna null - para facilitar em casos onde formulários podem ter
     * campos numéricos vazios.
     *
     * @param value String numérica
     * @return Float Objeto Float ou null caso receba uma String vazia ou nula
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static Float stringToFloat(String value) throws CustomException {
        if (value == null || value.equals("")) {
            return null;
        }

        Float floatValue = null;
        try {
            floatValue = java.lang.Float.parseFloat(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para Float.", e);
        }
        return floatValue;
    }

    /**
     * Converte uma String para um tipo primitivo float.
     *
     * @param value String numérica
     * @return float primitivo
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static float stringToFloatPrimitive(String value) throws CustomException {
        try {
            return java.lang.Float.parseFloat(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para float.", e);
        }
    }

    /**
     * Converte uma String para um objeto Double. Caso a String seja vazia ou
     * nula, retorna null - para facilitar em casos onde formulários podem ter
     * campos numéricos vazios.
     *
     * @param value String numérica
     * @return Double Objeto Double ou null caso receba uma String vazia ou nula
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static Double stringToDouble(String value) throws CustomException {
        if (value == null || value.equals("")) {
            return null;
        }

        Double doubleValue = null;
        try {
            doubleValue = java.lang.Double.parseDouble(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para Double.", e);
        }
        return doubleValue;
    }

    /**
     * Converte uma String para um tipo primitivo double.
     *
     * @param value String numérica
     * @return double primitivo
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static double stringToDoublePrimitive(String value) throws CustomException {
        try {
            return java.lang.Double.parseDouble(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para double.", e);
        }
    }

    /**
     * Converte uma String para um objeto Boolean. Caso a String seja vazia ou
     * nula, retorna null - para facilitar em casos onde formulários podem ter
     * campos numéricos vazios.
     *
     * @param value String booleana
     * @return Boolean Objeto Boolean ou null caso receba uma String vazia ou
     * nula
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static Boolean stringToBoolean(String value) throws CustomException {
        if (value == null || value.equals("")) {
            return null;
        }

        Boolean booleanValue = null;
        try {
            if ((value.toLowerCase().equals("true")) || (value.toLowerCase().equals("s")) || (value.equals("1"))) {
                booleanValue = true;
            } else if ((value.toLowerCase().equals("false")) || (value.toLowerCase().equals("n")) || (value.equals("0"))) {
                booleanValue = false;
            } else {
                throw new Exception();
            }
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para Boolean.", e);
        }

        return booleanValue;
    }

    /**
     * Converte uma String para um objeto Boolean. Caso a String seja vazia ou
     * nula, retorna null - para facilitar em casos onde formulários podem ter
     * campos numéricos vazios.
     *
     * @param value String booleana
     * @return Boolean Objeto Boolean True se, e somente se, a String for igual
     * a "true". Caso contrário, retornará False ou null caso receba uma String
     * vazia ou nula
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static Boolean stringToBooleanDefFalse(String value) throws CustomException {
        if (value == null || value.equals("")) {
            return null;
        }

        Boolean booleanValue = null;
        try {
            booleanValue = java.lang.Boolean.parseBoolean(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para Boolean.", e);
        }
        return booleanValue;
    }

    /**
     * Converte uma String para um tipo primitivo boolean.
     *
     * @param value String numérica
     * @return boolean primitivo
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static boolean stringToBooleanPrimitive(String value) throws CustomException {
        try {
            if ((value.toLowerCase().equals("true")) || (value.equals("1"))) {
                return true;
            } else if ((value.toLowerCase().equals("false")) || (value.equals("0"))) {
                return false;
            } else {
                throw new Exception();
            }
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para boolean.", e);
        }
    }

    /**
     * Converte uma String para um tipo primitivo boolean.
     *
     * @param value String numérica
     * @return Boolean primitivo True se, e somente se, a String for igual a
     * "true". Caso contrário, retornará False ou null caso receba uma String
     * vazia ou nula
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static boolean stringToBooleanPrimitiveDefFalse(String value) throws CustomException {
        try {
            return java.lang.Boolean.parseBoolean(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para boolean.", e);
        }
    }

    /**
     * Converte uma String para um objeto Date. Caso a String seja vazia ou
     * nula, retorna null - para facilitar em casos onde formulários podem ter
     * campos de datas vazios.
     *
     * @param value String no formato da constante
     * @param mask Máscara de data na qual a String será formatada
     * @return Date Objeto Date ou null caso receba uma String vazia ou nula
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static Date stringToDate(String value, String mask) throws CustomException {
        if (value == null || value.equals("")) {
            return null;
        }

        Date dateValue = null;
        try {
            DateFormat dateFormat = new SimpleDateFormat(mask);
            dateValue = (java.util.Date) dateFormat.parse(value);
        } catch (ParseException e) {
            throw new CustomException("Falha ao converter a String " + value + " para Date.", e);
        }

        return dateValue;
    }

    /**
     * Converte uma String para um objeto Character. Caso a String seja vazia ou
     * nula, retorna null - para facilitar em casos onde formulários podem ter
     * campos numéricos vazios.
     *
     * @param value String texto
     * @return Character Objeto Character ou null caso receba uma String vazia
     * ou nula
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static Character stringToCharacter(String value) throws CustomException {
        if (value == null || value.equals("")) {
            return null;
        }

        Character characterValue = null;
        try {
            characterValue = java.lang.Character.valueOf(value.charAt(0));
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para Character.", e);
        }
        return characterValue;
    }

    /**
     * Converte uma String para um tipo primitivo char.
     *
     * @param value String texto
     * @return char char primitivo
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static char stringToCharPrimitive(String value) throws CustomException {
        try {
            return value.charAt(0);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para char.", e);
        }
    }

    /**
     * Converte uma String para um objeto BigInteger. Caso a String seja vazia
     * ou nula, retorna null - para facilitar em casos onde formulários podem
     * ter campos numéricos vazios.
     *
     * @param value String numérica
     * @return BigInteger Objeto BigInteger ou null caso receba uma String vazia
     * ou nula
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static BigInteger stringToBigInteger(String value) throws CustomException {
        if (value == null || value.equals("")) {
            return null;
        }

        BigInteger bigIntegerValue = null;
        try {
            bigIntegerValue = new java.math.BigInteger(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para BigInteger.", e);
        }
        return bigIntegerValue;
    }

    /**
     * Converte uma String para um objeto BigDecimal. Caso a String seja vazia
     * ou nula, retorna null - para facilitar em casos onde formulários podem
     * ter campos numéricos vazios.
     *
     * @param value String numérica
     * @return BigDecimal Objeto BigDecimal ou null caso receba uma String vazia
     * ou nula
     * @throws CustomException Caso a String esteja no formato errado
     */
    public static BigDecimal stringToBigDecimal(String value) throws CustomException {
        if (value == null || value.equals("")) {
            return null;
        }

        BigDecimal bigDecimalValue = null;
        try {
            bigDecimalValue = new java.math.BigDecimal(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a String " + value + " para BigDecimal.", e);
        }
        return bigDecimalValue;
    }

    /**
     * Faz o cast do objeto String para a classe passada por parâmetro.
     *
     * @param value
     * @param castClass
     * @return Object
     */
    public static Object castString(String value, Class castClass) throws CustomException {
        try {
            if (value == null || value.equals("")) {
                return null;
            }

            String className = castClass.getName();

            if (className.equals(java.lang.Byte.class.getName())) {
                return stringToByte(value);
            } else if (className.equals(byte.class.getName())) {
                return stringToBytePrimitive(value);
            } else if (className.equals(java.lang.Short.class.getName())) {
                return stringToShort(value);
            } else if (className.equals(short.class.getName())) {
                return stringToShortPrimitive(value);
            } else if (className.equals(java.lang.Integer.class.getName())) {
                return stringToInteger(value);
            } else if (className.equals(int.class.getName())) {
                return stringToIntegerPrimitive(value);
            } else if (className.equals(java.lang.Long.class.getName())) {
                return stringToLong(value);
            } else if (className.equals(long.class.getName())) {
                return stringToLongPrimitive(value);
            } else if (className.equals(java.lang.Float.class.getName())) {
                return stringToFloat(value);
            } else if (className.equals(float.class.getName())) {
                return stringToFloatPrimitive(value);
            } else if (className.equals(java.lang.Double.class.getName())) {
                return stringToDouble(value);
            } else if (className.equals(double.class.getName())) {
                return stringToDoublePrimitive(value);
            } else if (className.equals(java.lang.Boolean.class.getName())) {
                return stringToBoolean(value);
            } else if (className.equals(boolean.class.getName())) {
                return stringToBooleanPrimitive(value);
            } else if (className.equals(java.util.Date.class.getName())) {
                return stringToDate(value, ConsUtil.FORMAT_MASK_DATE);
            } else if (className.equals(char.class.getName())) {
                return stringToCharPrimitive(value);
            } else if (className.equals(java.lang.Character.class.getName())) {
                return stringToCharacter(value);
            } else if (className.equals(java.math.BigInteger.class.getName())) {
                return stringToBigInteger(value);
            } else if (className.equals(java.math.BigDecimal.class.getName())) {
                return stringToBigDecimal(value);
            } else if (className.equals(java.lang.String.class.getName())) {
                return value;
            } else {
                return castClass.cast(value);
            }
        } catch (CustomException e) {
            throw e;
        } catch (Exception e) {
            throw new CustomException("Falha ao fazer cast da String " + value + " para " + castClass.getName(), e);
        }
    }

    /**
     * Converte um tipo Date para String.
     *
     * @param value Date
     * @param mask Máscara de data na qual a String será formatada
     * @return String
     * @throws CustomException Caso ocorra um erro de conversão
     */
    public static String dateToString(Date value, String mask) throws CustomException {
        if (value == null) {
            return null;
        }

        String dateValue = null;
        try {
            DateFormat dateFormat = new SimpleDateFormat(mask);
            dateValue = dateFormat.format(value);
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a data " + value + " para String.", e);
        }

        return dateValue;
    }

    /**
     * Retorna a hora por extenso referente à quantidade de segundos passada por
     * parâmetro.
     *
     * @param segundos
     * @return String
     */
    public static String getHoraExtenso(long segundos) {
        long iSegundos = segundos;
        long iMinutos = 0;
        long iHoras = 0;
        long iDias = 0;
        String result = "";

        while (iSegundos >= 60) {
            iMinutos += 1;
            iSegundos -= 60;
        }

        while (iMinutos >= 60) {
            iHoras += 1;
            iMinutos -= 60;
        }

        while (iHoras >= 24) {
            iDias += 1;
            iHoras -= 24;
        }

        if (iDias > 0) {
            result = result + iDias;
            if (iDias == 1) {
                result += " dia ";
            } else {
                result += " dias ";
            }
        }

        if (iHoras > 0) {
            result = result + iHoras;
            if (iHoras == 1) {
                result += " hora ";
            } else {
                result += " horas ";
            }
        }

        if (iMinutos > 0) {
            result = result + iMinutos;
            if (iMinutos == 1) {
                result += " minuto ";
            } else {
                result += " minutos ";
            }
        }

        if (iSegundos > 0) {
            result = result + iSegundos;
            if (iSegundos == 1) {
                result += " segundo ";
            } else {
                result += " segundos ";
            }
        }

        return result;
    }

    public static String rPad(String string, Integer length, char chr) {
        return string
                + String.format("%" + (length - string.length()) + "s", "")
                .replace(" ", String.valueOf(chr));
    }

    public static String lPad(String string, Integer length, char chr) {
        return String.format("%" + (length - string.length()) + "s", "")
                .replace(" ", String.valueOf(chr))
                + string;
    }

    /**
     * Retorna a data atual do servidor.
     *
     * @return Date dd/MM/yyyy
     */
    public static Date getDataAtual(String mask) throws CustomException {
        try {
            DateFormat dateFormat = new SimpleDateFormat(mask);
            return (java.util.Date) dateFormat.parse(dateFormat.format(Calendar.getInstance().getTime()));
        } catch (Exception e) {
            throw new CustomException("Falha ao converter a data atual.", e);
        }
    }

    /**
     * Soma a quantidade de minutos à data passada por parâmetro.
     *
     * @param data
     * @param minutos
     * @return Date
     */
    public static Date somarMinutos(Date data, int minutos) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(data);
        calendar.add(Calendar.MINUTE, minutos);
        return calendar.getTime();
    }

    /**
     * Soma a quantidade de segundos à data passada por parâmetro.
     *
     * @param data
     * @param segundos
     * @return Date
     */
    public static Date somarSegundos(Date data, int segundos) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(data);
        calendar.add(Calendar.SECOND, segundos);
        return calendar.getTime();
    }

    /**
     * Soma a quantidade de dias à data passada por parâmetro.
     *
     * @param data
     * @param dias
     * @return Date
     */
    public static Date somarDias(Date data, int dias) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(data);
        calendar.add(Calendar.DATE, dias);
        return calendar.getTime();
    }

    /**
     * Soma a quantidade de meses à data passada por parâmetro.
     *
     * @param data
     * @param meses
     * @return Date
     */
    public static Date somarMeses(Date data, int meses) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(data);
        calendar.add(Calendar.MONTH, meses);
        return calendar.getTime();
    }

    /**
     * Soma a quantidade de anos à data passada por parâmetro.
     *
     * @param data
     * @param anos
     * @return Date
     */
    public static Date somarAnos(Date data, int anos) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(data);
        calendar.add(Calendar.YEAR, anos);
        return calendar.getTime();
    }

    //FORMAT FUNCTIONS
    /**
     * Formata uma String com delimitador de caracteres inserindo 3 pontos no
     * fim. Retorna a String original se o tamanho da mesma for menor que o
     * delimitador.
     *
     *
     * @param texto
     * @param delimitador
     * @return String
     */
    public static String formatStringDelimitador(String texto, int delimitador) {
        if (texto.length() > delimitador) {
            String returnString = texto.substring(0, delimitador);
            return (returnString += "...").trim();
        } else {
            return texto;
        }
    }

    /**
     * Formata um número inteiro no padrão de milhar utilizando pontuação
     *
     *
     * @param numero
     * @return String
     */
    public static String formatMilhar(int number) {
        NumberFormat format = new DecimalFormat("###,###,##0");
        String returnString = format.format(number);
        return returnString;
    }

    /**
     * Formata um valor em bytes para o seu valor adequado em medidas (B, KB,
     * MB, GB, TB).
     *
     *
     * @param valor
     * @param patern
     * @return String
     */
    public static String convertPowerOfByte(long valor, String patern) {
        String[] powerOfByte = {"B", "KB", "MB", "GB", "TB"};
        int potencia = 0;
        int proxima = potencia;
        boolean testaPotenciaActual;
        boolean testaPotenciaSeguinte;
        do {
            proxima = potencia + 1;
            testaPotenciaActual = (Math.pow(2, potencia * 10) <= valor);
            testaPotenciaSeguinte = (valor < Math.pow(2, proxima * 10));
            potencia++;

        } while (!(testaPotenciaActual && testaPotenciaSeguinte));

        potencia--;
        DecimalFormat myFormatter = new DecimalFormat(patern);

        return myFormatter.format(valor / Math.pow(2, potencia * 10)) + " " + powerOfByte[potencia];
    }

    /**
     * Função responsável por converter os campos do tipo String das entidades
     * para upperCase. Precede a gravação dos dados no banco.
     *
     * @param entity
     * @return void
     */
    public static void genericEntityUpperCase(Object entity) throws CustomException {
        try {
            Class reflectionClass = entity.getClass();
            Field[] classFields = reflectionClass.getDeclaredFields();

            for (Field field : classFields) {
                //DETERMINA O TIPO (CLASSE) DO ATRIBUTO

                String tipo = field.getType().toString();
                field.setAccessible(true);

                if (field.getType().equals(String.class)) {
                    for (Method method : reflectionClass.getDeclaredMethods()) {
                        if (method.getName().equals("set" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1))) {
                            if (field.get(entity) != null) {
                                method.invoke(entity, field.get(entity).toString().toUpperCase());
                                break;
                            }
                        }
                    }
                } else if (!field.getType().isPrimitive()) {
                    genericEntityUpperCase(field.getType());
                }
            }
        } catch (Exception e) {
            throw new CustomException("Falha ao aplicar UpperCase na entidade: " + entity.toString(), e);
        }
    }

    /**/
    public static String getMes(int mes) {
        String mesNome[] = {
            "Janeiro",
            "Fevereiro",
            "Março",
            "Abril",
            "Maio",
            "Junho",
            "Julho",
            "Agosto",
            "Setembro",
            "Outubro",
            "Novembro",
            "Dezembro"
        };
        return mesNome[mes - 1];
    }

    /**
     * Aplica uma máscara pré-definida a uma String.
     *
     * Padrão: "SÍMBOLO | SEPARADOR DE MILHAR | SEPARADOR DE DECIMAL | PRECISÃO
     * (CASAS APÓS A VIRGULA)".
     *
     * @param value
     * @param pattern
     * @return String
     *
     */
    public static String formatCurrencyString(String value, String pattern) throws CustomException {

        try {
            if (value != null && !value.equals("")) {

                // == TRATA A MÁSCARA PARA OBTER INFORMAÇÕES
                // ===============================================

                String[] patternParam = pattern.split("\\|");

                String prefix = patternParam[0].trim();
                String thousandSeparator = patternParam[1].trim();
                String decimalSeparator = patternParam[2].trim();
                int precisionScale = Integer.parseInt(patternParam[3].trim());

                // == TRATA A STRING A SER CONVERTIDA
                // ===============================================

                String[] originalValue = value.split("\\.");
                String finalString = "";

                // == APLICA A MÁSCARA NA STRING
                // ===============================================

                //PREFIXO
                if (prefix != null && !prefix.equals("")) {
                    finalString += prefix;
                }

                //VALOR INTEIRO || TRATAMENTO DE MILHAR

                if (originalValue.length > 0) {

                    finalString += " " + formatMilhar(Integer.parseInt(originalValue[0]));
                } else {
                    finalString += " " + formatMilhar(Integer.parseInt(value));
                }

                //VALOR DECIMAL || TRATAMENTO DE SEPARADOR DECIMAL

                if (decimalSeparator != null && !decimalSeparator.equals("") && precisionScale > 0) {

                    if (originalValue.length > 1) {

                        finalString += decimalSeparator + originalValue[1];

                        //TRATA PRECISÃO DAS CASAS DECIMAIS
                        if (originalValue[1].length() < precisionScale) {
                            for (int cont = originalValue[1].length(); cont < precisionScale; cont++) {
                                finalString += "0";
                            }
                        }

                    } else {

                        finalString += decimalSeparator;
                        for (int cont = 0; cont < precisionScale; cont++) {
                            finalString += "0";
                        }
                    }

                }


                return finalString;

            } else {

                return null;
            }
        } catch (Exception e) {
            throw new CustomException("Falha ao aplicar a máscara monetária " + pattern + " no valor " + value + ".", e);
        }
    }

    /**
     * Remove uma máscara pré-definida a uma String. (CONVERTER READY)
     *
     * Padrão: "SÍMBOLO | SEPARADOR DE MILHAR | SEPARADOR DE DECIMAL | PRECISÃO
     * (CASAS APÓS A VIRGULA)".
     *
     * @param value
     * @param pattern
     * @return String
     *
     */
    public static Object unformatCurrencyString(String value, String pattern) throws CustomException {

        // == TRATA A MÁSCARA PARA OBTER INFORMAÇÕES
        // ===============================================

        try {
            if (value != null && !value.isEmpty()) {

                String[] patternParam = pattern.split("\\|");

                String prefix = patternParam[0].trim();
                String thousandSeparator = patternParam[1].trim();
                String decimalSeparator = patternParam[2].trim();

                // == REMOVE ITENS USANDO REPLACE (SEPARADAMENTE)
                // ==============================================

                value = value.replaceAll("[" + prefix + " " + thousandSeparator + "]", "");
                value = value.replaceAll(decimalSeparator, ".");

            }

            return value;
        } catch (Exception e) {
            throw new CustomException("Falha ao remover máscara monetária " + pattern + " do valor " + value + ".", e);
        }
    }

    /**
     * Remove uma máscara pré-definida a uma String sem possuir uma máscara
     * definida (FORÇE). (CONVERTER READY)
     *
     *
     * @param value
     * @param pattern
     * @return String
     *
     */
    public static Object unformatCurrencyStringForce(String value) throws CustomException {

        try {
            // == VAR
            // =================

            String returnString = "";

            // VARRE A STRING, BUSCANDO APENAS POR CARACTERES NUMÉRICOS E O SEPARADOR DECIMAL

            if (value != null && !value.equals("")) {
                for (int cont = 0; cont < value.length(); cont++) {
                    if (isLong(String.valueOf(value.charAt(cont)))) {
                        returnString += value.charAt(cont);
                    } else if (value.charAt(cont) == ',') {
                        returnString += '.';
                    }
                }
            }

            return returnString;
        } catch (Exception e) {
            throw new CustomException("Falha ao remover máscara do valor " + value + ".", e);
        }
    }

    /**
     * Aplica uma máscara ESTÁTICA pré-definida a uma String. (CONVERTER READY)
     *
     * Padrão: (9 OU #) PARA VALORES FIXOS + (0) VARIAVEIS + DELIMITADORES
     *
     * @param value
     * @param pattern
     * @return String
     *
     */
    public static String formatMaskString(String value, String pattern) throws CustomException {

        try {
            //VARRE O PATTERN, ALOCANDO O VALOR A CASA CORRESPONDENTE

            char[] patternArray = pattern.toCharArray();
            String returnValue = "";
            int valueCont = 0;

            for (int cont = 0; cont < patternArray.length; cont++) {
                if (patternArray[cont] == '9' || patternArray[cont] == '#') {
                    if (valueCont < value.length()) {
                        patternArray[cont] = value.charAt(valueCont);
                        returnValue += patternArray[cont];
                        valueCont++;
                    } else {
                        returnValue += "_";
                    }

                } else {
                    returnValue += patternArray[cont];
                }


            }

            return returnValue;
        } catch (Exception e) {
            throw new CustomException("Falha ao aplicar máscara " + pattern + " no valor " + value + ".", e);
        }
    }

    /**
     * Aplica uma máscara ESTÁTICA pré-definida a uma String de DATE. (CONVERTER
     * READY)
     *
     * Padrão:
     *
     * d = DIA M = MÊS y = ANO H = HORA m = MINUTO s = SEGUNDO
     *
     * @param value
     * @param pattern
     * @return String
     *
     */
    public static String formatMaskDate(String value, String pattern) throws CustomException {

        try {
            // == VARIÁVEIS
            // =====================

            //DEFINE CONJUNTO DE SIMBOLOS DA MÁSCARA DATE
            char[] patternSymbol = {'d', 'M', 'y', 'H', 'm', 's'};
            char[] patternArray = pattern.toCharArray();
            String returnValue = "";
            int valueCont = 0;
            Boolean isCharSymbol = false;

            //VARRE O PATTERN, ALOCANDO O VALOR A CASA CORRESPONDENTE

            for (int cont = 0; cont < patternArray.length; cont++) {

                for (int contSymbol = 0; contSymbol < patternSymbol.length; contSymbol++) {
                    if (patternArray[cont] == patternSymbol[contSymbol]) {

                        isCharSymbol = true;
                        break;

                    }
                }

                if (valueCont < value.length()) {

                    if (isCharSymbol) {
                        returnValue += value.charAt(valueCont);
                        valueCont++;
                    } else {
                        returnValue += patternArray[cont];
                    }

                } else {
                    returnValue += "_";
                }


            }

            return returnValue;
        } catch (Exception e) {
            throw new CustomException("Falha ao aplicar máscara de data " + pattern + " no valor " + value + ".", e);
        }
    }

    public static String formatMaskCPF(Long cpf) throws CustomException {
        if ((cpf == null) || (cpf.toString().length() != 11)) {
            return "";
        } else {
            return formatMaskString(cpf.toString(), ConsUtil.FORMAT_MASK_CPF);
        }
    }

    public static String formatMaskCNPJ(Long cnpj) throws CustomException {
        if ((cnpj == null) || (cnpj.toString().length() != 14)) {
            return "";
        } else {
            return formatMaskString(cnpj.toString(), ConsUtil.FORMAT_MASK_CNPJ);
        }
    }

    /**
     * Verifica se um valor é Long
     *
     *
     * @param value
     * @return Boolean
     *
     */
    public static Boolean isLong(String value) {
        try {
            Long.parseLong(value);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    //Retorna String removendo zeros a esquerda
    public static String removerZerosEsquerda(String texto) {
        return texto.replaceAll("^([0]+)", "");
    }

    /**
     * Valida o CPF passado por parâmetro.
     *
     *
     * @param cpf
     * @return boolean
     *
     */
    public static boolean validarCPF(Long cpf) {
        //return ((cpf != null) && (cpf.toString().length() == 11) && (validarCPF(cpf.toString())));
        String cpfString = String.format("%011d", cpf);
        return ((cpf != null) && (cpfString.length() == 11) && (validarCPF(cpfString)));
    }

    private static boolean validarCPF(String strCpf) {
        int iDigito1Aux = 0, iDigito2Aux = 0, iDigitoCPF;
        int iDigito1 = 0, iDigito2 = 0, iRestoDivisao = 0;
        String strDigitoVerificador, strDigitoResultado;

        if (!strCpf.substring(0, 1).equals("")) {
            try {
                strCpf = strCpf.replace('.', ' ');
                strCpf = strCpf.replace('-', ' ');
                strCpf = strCpf.replaceAll(" ", "");
                for (int iCont = 1; iCont < strCpf.length() - 1; iCont++) {
                    iDigitoCPF = Integer.valueOf(strCpf.substring(iCont - 1, iCont)).intValue();
                    iDigito1Aux = iDigito1Aux + (11 - iCont) * iDigitoCPF;
                    iDigito2Aux = iDigito2Aux + (12 - iCont) * iDigitoCPF;
                }
                iRestoDivisao = (iDigito1Aux % 11);
                if (iRestoDivisao < 2) {
                    iDigito1 = 0;
                } else {
                    iDigito1 = 11 - iRestoDivisao;
                }
                iDigito2Aux += 2 * iDigito1;
                iRestoDivisao = (iDigito2Aux % 11);
                if (iRestoDivisao < 2) {
                    iDigito2 = 0;
                } else {
                    iDigito2 = 11 - iRestoDivisao;
                }
                strDigitoVerificador = strCpf.substring(strCpf.length() - 2, strCpf.length());
                strDigitoResultado = String.valueOf(iDigito1) + String.valueOf(iDigito2);
                return strDigitoVerificador.equals(strDigitoResultado);
            } catch (Exception e) {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * Valida o CNPJ passado por parâmetro.
     *
     *
     * @param cnpj
     * @return boolean
     *
     */
    public static boolean validarCNPJ(Long cnpj) {
        //return ((cnpj != null) && (cnpj.toString().length() == 14) && (validarCNPJ(cnpj.toString())));
        String cnpjString = String.format("%014d", cnpj);
        return ((cnpj != null) && (cnpjString.length() == 14) && (validarCNPJ(cnpjString)));
    }

    private static boolean validarCNPJ(String strCNPJ) {
        int iSoma = 0, iDigito;
        char[] chCaracteresCNPJ;
        String strCNPJ_Calculado;

        if (!strCNPJ.substring(0, 1).equals("")) {
            try {
                strCNPJ = strCNPJ.replace('.', ' ');
                strCNPJ = strCNPJ.replace('/', ' ');
                strCNPJ = strCNPJ.replace('-', ' ');
                strCNPJ = strCNPJ.replaceAll(" ", "");
                strCNPJ_Calculado = strCNPJ.substring(0, 12);
                if (strCNPJ.length() != 14) {
                    return false;
                }
                chCaracteresCNPJ = strCNPJ.toCharArray();
                for (int i = 0; i < 4; i++) {
                    if ((chCaracteresCNPJ[i] - 48 >= 0) && (chCaracteresCNPJ[i] - 48 <= 9)) {
                        iSoma += (chCaracteresCNPJ[i] - 48) * (6 - (i + 1));
                    }
                }
                for (int i = 0; i < 8; i++) {
                    if ((chCaracteresCNPJ[i + 4] - 48 >= 0) && (chCaracteresCNPJ[i + 4] - 48 <= 9)) {
                        iSoma += (chCaracteresCNPJ[i + 4] - 48) * (10 - (i + 1));
                    }
                }
                iDigito = 11 - (iSoma % 11);
                strCNPJ_Calculado += ((iDigito == 10) || (iDigito == 11)) ? "0" : Integer.toString(iDigito);
                /* Segunda parte */
                iSoma = 0;
                for (int i = 0; i < 5; i++) {
                    if ((chCaracteresCNPJ[i] - 48 >= 0) && (chCaracteresCNPJ[i] - 48 <= 9)) {
                        iSoma += (chCaracteresCNPJ[i] - 48) * (7 - (i + 1));
                    }
                }
                for (int i = 0; i < 8; i++) {
                    if ((chCaracteresCNPJ[i + 5] - 48 >= 0) && (chCaracteresCNPJ[i + 5] - 48 <= 9)) {
                        iSoma += (chCaracteresCNPJ[i + 5] - 48) * (10 - (i + 1));
                    }
                }
                iDigito = 11 - (iSoma % 11);
                strCNPJ_Calculado += ((iDigito == 10) || (iDigito == 11)) ? "0" : Integer.toString(iDigito);
                return strCNPJ.equals(strCNPJ_Calculado);
            } catch (Exception e) {
                return false;
            }
        } else {
            return false;
        }
    }

    public static String nvl(String value1, String value2) {
        if ((value1 == null) || (value1.isEmpty())) {
            return value2;
        } else {
            return value1;
        }
    }

    public static Integer nvl(Integer value1, Integer value2) {
        if (value1 == null) {
            return value2;
        } else {
            return value1;
        }
    }

    public static Short nvl(Short value1, Short value2) {
        if (value1 == null) {
            return value2;
        } else {
            return value1;
        }
    }

    public static Long nvl(Long value1, Long value2) {
        if (value1 == null) {
            return value2;
        } else {
            return value1;
        }
    }

    public static BigDecimal nvl(BigDecimal value1, BigDecimal value2) {
        if (value1 == null) {
            return value2;
        } else {
            return value1;
        }
    }

    public static Boolean nvl(Boolean value1, Boolean value2) {
        if (value1 == null) {
            return value2;
        } else {
            return value1;
        }
    }

    public static String getExtencaoArquivo(String arquivo) {
        String ext[] = arquivo.split("\\.");
        int i = ext.length;
        if (i > 1) {
            return ext[i - 1];
        } else {
            return null;
        }
    }
}
